home *** CD-ROM | disk | FTP | other *** search
- /*
- * File stolen from WAMPES 921229, modified for compatibility with JNOS and my
- * tastes, and left to sink or swim. Blub! ++bsa
- *
- * The actual structure is much closer to that of JNOS than to WAMPES. The
- * reason is that WAMPES uses these weirdball I/O hooks... We will use the
- * "classic" interface, modified by the use of register_fd(). (Actually, the
- * weirdball I/O hooks are just WAMPES's version of register_fd(). The API
- * for WAMPES is a heck of a lot hairier, though.)
- */
-
- #include <sys/types.h>
-
- #include <fcntl.h>
- #include <stdio.h>
- #include <string.h>
- #include <termios.h>
- #include <sys/time.h>
- #include <errno.h>
-
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "iface.h"
- #include "asy.h"
- #include "timer.h"
- #include "unixasy.h"
- #include "hardware.h"
- #include "devparam.h"
- #include "commands.h"
- #include "cmdparse.h"
-
- extern int chmod __ARGS((const char *, unsigned));
-
- static int find_speed __ARGS((long speed));
- static void pasy __ARGS((struct asy *asyp));
- static void asy_tx __ARGS((int, void *, void *));
- static void asy_input __ARGS((int, void *, void *));
-
- struct asy Asy[ASY_MAX];
-
- /*---------------------------------------------------------------------------*/
-
- static int dorxqueue __ARGS((int argc, char **argv, void *p));
- static int dotxqueue __ARGS((int argc, char **argv, void *p));
- static int dobufsize __ARGS((int argc, char **argv, void *p));
- static int doasy2stat __ARGS((int argc, char **argv, void *p));
-
- static struct cmds AsyPcmds[] =
- {
- "rxqueue", dorxqueue, 0, 0, NULLCHAR,
- "txqueue", dotxqueue, 0, 0, NULLCHAR,
- "bufsize", dobufsize, 0, 0, NULLCHAR,
- "status", doasy2stat, 0, 0, NULLCHAR,
- 0,
- };
-
- /*---------------------------------------------------------------------------*/
-
- static struct {
- long speed;
- speed_t flags;
- } speed_table[] = {
- #ifdef B50
- 50, B50,
- #endif
- #ifdef B75
- 75, B75,
- #endif
- #ifdef B110
- 110, B110,
- #endif
- #ifdef B134
- 134, B134,
- #endif
- #ifdef B150
- 150, B150,
- #endif
- #ifdef B200
- 200, B200,
- #endif
- #ifdef B300
- 300, B300,
- #endif
- #ifdef B600
- 600, B600,
- #endif
- #ifdef B900
- 900, B900,
- #endif
- #ifdef B1200
- 1200, B1200,
- #endif
- #ifdef B1800
- 1800, B1800,
- #endif
- #ifdef B2400
- 2400, B2400,
- #endif
- #ifdef B3600
- 3600, B3600,
- #endif
- #ifdef B4800
- 4800, B4800,
- #endif
- #ifdef B7200
- 7200, B7200,
- #endif
- #ifdef B9600
- 9600, B9600,
- #endif
- #ifdef B19200
- 19200, B19200,
- #endif
- #ifdef B38400
- 38400, B38400,
- #endif
- #ifdef B57600
- 57600, B57600,
- #endif
- #ifdef B115200
- 115200, B115200,
- #endif
- #ifdef B230400
- 230400, B230400,
- #endif
- #ifdef B460800
- 460800, B460800,
- #endif
- -1, 0
- };
-
- /*---------------------------------------------------------------------------*/
-
- static int
- find_speed(speed)
- long speed;
- {
- int i;
-
- i = 0;
- while (speed_table[i].speed < speed && speed_table[i+1].speed > 0)
- i++;
- return i;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Initialize asynch port "dev" */
- int
- asy_init(dev,ifp,arg1,arg2,bufsize,trigchar,monitor,speed,force,triglevel)
- int dev;
- struct iface *ifp;
- char *arg1,*arg2; /* Attach args for address and vector */
- int16 bufsize;
- int trigchar;
- char monitor;
- long speed;
- int force;
- int triglevel;
- {
- register struct asy *ap;
- char filename[80];
- char *ifn;
- int sp, fd;
- struct termios termios;
-
- ap = &Asy[dev];
-
- /* UUCP locking with ASCII pid */
- strcpy(ap->uulock, "/usr/spool/uucp/LCK..");
- strcat(ap->uulock, arg1);
- for (;;)
- {
- if ((fd = open(ap->uulock, O_WRONLY|O_CREAT|O_EXCL, 0644)) != -1 ||
- errno != EEXIST)
- break;
- /* read pid, unlink and retry if proc no longer exists */
- if ((fd = open(ap->uulock, O_RDONLY)) == -1)
- continue; /* timing is everything */
- filename[read(fd, filename, 10)] = '\0';
- close(fd);
- sscanf(filename, "%d", &fd);
- if (kill(fd, 0) == -1 && errno == ESRCH)
- {
- tprintf("Removing stale lockfile for %s\n", arg1);
- unlink(ap->uulock);
- continue;
- }
- tprintf("/dev/%s is locked\n", arg1);
- ap->uulock[0] = '\0'; /* so it won't clobber existing lock */
- goto Fail;
- }
- if (fd == -1)
- {
- tprintf("Can't lock /dev/%s: %s\n", arg1, strerror(errno));
- ap->uulock[0] = '\0';
- goto Fail;
- }
- chmod(ap->uulock, 0644); /* beware of overly restrictive umask */
- sprintf(filename, "%10d\n", getpid());
- write(fd, filename, 11);
- close(fd);
-
- strcpy(filename, "/dev/");
- strcat(filename, arg1);
- if ((fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
- {
- tprintf("Can't open port: %s\n", strerror(errno));
- goto Fail;
- }
- ap->flags = 0;
- ap->iface = ifp;
- sp = find_speed(speed);
- ap->speed = speed_table[sp].speed;
- memset((char *) &termios, 0, sizeof(termios));
- termios.c_iflag = IGNBRK|IGNPAR;
- termios.c_cflag = CS8|CREAD|CLOCAL|speed_table[sp].flags;
- termios.c_cc[VTIME] = 2;
- if ((ap->pktsize = triglevel & 255))
- termios.c_cc[VMIN] = triglevel & 255;
- if (cfsetispeed(&termios, speed_table[sp].flags) == -1)
- {
- tprintf("Can't set speed: %s\n", strerror(errno));
- goto Fail;
- }
- if (cfsetospeed(&termios, speed_table[sp].flags) == -1)
- {
- tprintf("Can't set speed: %s\n", strerror(errno));
- goto Fail;
- }
- if (tcsetattr(fd, TCSANOW, &termios) == -1)
- {
- tprintf("Can't configure port: %s\n", strerror(errno));
- goto Fail;
- }
- /* security: port won't work until re-opened */
- if ((ap->fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
- {
- tprintf("Can't reopen port: %s\n", strerror(errno));
- goto Fail;
- }
- close(fd);
-
- /* new asy parameters, defaulted for now */
- ap->rxq = 1; /* disable queueing */
- ap->txq = 1;
- ap->rxbuf = bufsize;
-
- /* clear statistics */
- ap->rxints = 0;
- ap->txints = 0;
- ap->rxchar = 0;
- ap->txchar = 0;
- ap->rxput = 0;
- ap->rxovq = 0;
- ap->rxblock = 0;
- ap->txget = 0;
- ap->txovq = 0;
- ap->txblock = 0;
-
- ifp->txproc = newproc(ifn = if_name(ifp," tx"),
- 256, asy_tx, dev, ifp, NULL, 0);
- free(ifn);
- ap->rxproc = newproc(ifn = if_name(ifp, " hw"),
- 256, asy_input, dev, ifp, NULL, 0);
- free(ifn);
-
- register_io(ap->fd, &ap->fd);
-
- return 0;
-
- Fail:
- rflush(); /* make sure the message gets out */
- if (fd != -1)
- close(fd);
- /* Unlock port */
- if (ap->uulock[0])
- unlink(ap->uulock);
- ap->uulock[0] = '\0';
- ap->iface = NULLIF;
- return -1;
- }
-
- /*---------------------------------------------------------------------------*/
-
- int
- asy_stop(ifp)
- struct iface *ifp;
- {
- register struct asy *ap;
-
- ap = &Asy[ifp->dev];
-
- if(ap->iface == NULLIF)
- return -1; /* Not allocated */
-
- unregister_io(ap->fd);
-
- if (ifp->txproc)
- killproc(ifp->txproc);
- ifp->txproc = 0;
-
- if (ap->rxproc)
- killproc(ap->rxproc);
- ap->rxproc = 0;
-
- ap->iface = NULLIF;
-
- free_q(&ap->sndq);
- close(ap->fd);
-
- free_q(&ap->rcvq);
-
- if (ap->uulock[0])
- unlink(ap->uulock);
- ap->uulock[0] = '\0';
-
- return 0;
- }
-
- void
- detach_all_asy()
- {
- register struct asy *ap;
-
- for (ap = Asy; ap != Asy + ASY_MAX; ap++)
- {
- if(ap->iface == NULLIF)
- break;
- unregister_io(ap->fd);
- if (ap->iface->txproc)
- killproc(ap->iface->txproc);
- ap->iface->txproc = 0;
- if (ap->rxproc)
- killproc(ap->rxproc);
- ap->rxproc = 0;
- ap->iface = NULLIF;
- free_q(&ap->sndq);
- free_q(&ap->rcvq);
- close(ap->fd);
- if (ap->uulock[0])
- unlink(ap->uulock);
- ap->uulock[0] = '\0';
- }
- }
-
-
- /*---------------------------------------------------------------------------*/
-
- /* Set asynch line speed */
- int
- asy_speed(dev, bps)
- int dev;
- long bps;
- {
- struct asy *asyp;
- int sp;
- struct termios termios;
-
- if(bps <= 0 || dev >= ASY_MAX)
- return -1;
- asyp = &Asy[dev];
- if(asyp->iface == NULLIF)
- return -1;
- if(bps == 0)
- return -1;
- sp = find_speed(bps);
- if (tcgetattr(asyp->fd, &termios))
- return -1;
- if (cfsetispeed(&termios, speed_table[sp].flags))
- return -1;
- if (cfsetospeed(&termios, speed_table[sp].flags))
- return -1;
- termios.c_cflag &= ~CBAUD;
- termios.c_cflag |= speed_table[sp].flags;
- if (tcsetattr(asyp->fd, TCSANOW, &termios))
- return -1;
- asyp->speed = speed_table[sp].speed;
- return 0;
- }
-
- /* Set termios VMIN (packet size) */
- int
- asy_vmin(dev, pktsize)
- int dev;
- long pktsize;
- {
- struct termios termios;
- struct asy *asyp;
-
- if (pktsize < 0 || pktsize > 255 || dev >= ASY_MAX)
- return -1;
- if ((asyp = &Asy[dev])->iface == NULLIF)
- return -1;
- if (tcgetattr(asyp->fd, &termios))
- return -1;
- termios.c_cc[VMIN] = asyp->pktsize = pktsize & 255;
- if (tcsetattr(asyp->fd, TCSANOW, &termios))
- return -1;
- return 0;
- }
-
- /* Set or clear RTS/CTS flow control */
- int
- asy_rts(dev, onoff)
- int dev;
- unsigned long onoff;
- {
- struct termios termios;
- struct asy *asyp;
-
- if ((asyp = &Asy[dev])->iface == NULLIF)
- return -1;
- if (tcgetattr(asyp->fd, &termios))
- return -1;
- /*
- * note sense is reversed as per DOS version, except that we default to
- * RTS/CTS being *off* for compatibility with earlier ALPHA versions
- */
- if (onoff)
- {
- asyp->flags &= ~ASY_RTSCTS;
- termios.c_cflag &= ~CRTSCTS;
- }
- else
- {
- asyp->flags |= ASY_RTSCTS;
- termios.c_cflag |= CRTSCTS;
- }
- if (tcsetattr(asyp->fd, TCSANOW, &termios))
- return -1;
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Asynchronous line I/O control */
- int32
- asy_ioctl(ifp, cmd, set, val)
- struct iface *ifp;
- int cmd;
- int set;
- int32 val;
- {
- struct asy *ap = &Asy[ifp->dev];
-
- switch(cmd){
- case PARAM_SPEED:
- if (set)
- asy_speed(ifp->dev, val);
- return ap->speed;
- case PARAM_MIN:
- if (set)
- asy_vmin(ifp->dev, val);
- return ap->pktsize;
- case PARAM_RTS:
- if (set)
- asy_rts(ifp->dev, val);
- return (ap->flags & ASY_RTSCTS) == 0;
- }
- return -1;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static void
- asy_input(dev, arg1, arg2)
- int dev;
- void *arg1, *arg2;
- {
- struct timeval tv;
- extern int errno;
- struct asy *ap;
- fd_set fds;
- char *buf;
- int i, c;
-
- ap = &Asy[dev];
- for (;;)
- {
- if (pwait(&ap->fd) != 0)
- return;
- ap->rxints++;
- buf = mallocw(ap->rxbuf);
-
- if (ap->pktsize)
- fcntl(ap->fd, F_SETFL, fcntl(ap->fd, F_GETFL, 0) & ~O_NONBLOCK);
- if ((i = read(ap->fd, buf, ap->rxbuf)) == 0 ||
- (!ap->pktsize && i == -1 && errno == EWOULDBLOCK))
- {
- if (ap->pktsize)
- fcntl(ap->fd, F_SETFL, fcntl(ap->fd, F_GETFL, 0) | O_NONBLOCK);
- ap->rxblock++;
- free(buf);
- continue;
- }
- if (i == -1)
- {
- tprintf("asy_input(%d): read error %d, shutting down\n", dev,
- errno);
- if (ap->pktsize)
- fcntl(ap->fd, F_SETFL, fcntl(ap->fd, F_GETFL, 0) | O_NONBLOCK);
- free(buf);
- return;
- }
- if ((c = ap->rxq) <= 0)
- c = 1;
- while (i > 0 && c > 0)
- {
- ap->rxchar += i;
- ap->rxput++;
- enqueue(&ap->rcvq, qdata(buf, i));
- c--;
- if (ap->pktsize)
- {
- /* can't just read to check for data, since it might block */
- FD_ZERO(&fds);
- FD_SET(ap->fd, &fds);
- tv.tv_sec = tv.tv_usec = 0;
- if (select(FD_SETSIZE, &fds, 0, 0, &tv) == 0)
- {
- i = -1;
- errno = EWOULDBLOCK;
- break;
- }
- }
- i = read(ap->fd, buf, ap->rxbuf);
- }
- free(buf);
- if (i == -1 && errno != EWOULDBLOCK)
- {
- tprintf("asy_input(%d): read error %d, shutting down\n", dev,
- errno);
- return;
- }
- if (ap->pktsize)
- fcntl(ap->fd, F_SETFL, fcntl(ap->fd, F_GETFL, 0) | O_NONBLOCK);
- if (c < 1 && ap->rxq > 1)
- ap->rxovq++;
- }
- }
-
- int
- get_asy(dev)
- int dev;
- {
- struct asy *ap;
-
- ap = &Asy[dev];
- if (ap->iface == NULLIF)
- return -1;
- while (!ap->rcvq)
- {
- if (pwait(&ap->rcvq) != 0)
- return -1; /* may not be dead, e.g. alarm in dialer */
- }
- return PULLCHAR(&ap->rcvq);
- }
-
- int
- doasystat(int argc,char **argv,void *p)
- {
- register struct asy *asyp;
- struct iface *ifp;
- int i;
-
- if(argc < 2){
- for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
- if(asyp->iface != NULLIF)
- pasy(asyp);
- }
- return 0;
- }
- for(i=1;i<argc;i++){
- if((ifp = if_lookup(argv[i])) == NULLIF){
- tprintf("Interface %s unknown\n",argv[i]);
- continue;
- }
- for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
- if(asyp->iface == ifp){
- pasy(asyp);
- break;
- }
- }
- if(asyp == &Asy[ASY_MAX])
- tprintf("Interface %s not asy\n",argv[i]);
- }
-
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static void
- pasy(asyp)
- struct asy *asyp;
- {
- tprintf("%s: %lu bps, ", asyp->iface->name, asyp->speed);
- if (asyp->pktsize)
- tprintf("packet size %d", asyp->pktsize);
- else
- tprintf("non-blocking");
- tprintf(", RTS/CTS %sabled", (asyp->flags & ASY_RTSCTS? "en": "dis"));
- tprintf(", carrier %sabled\n", (asyp->flags & ASY_CARR? "en": "dis"));
- tprintf(" RX: ints %lu chars %lu puts %lu buf %d rxqueue %d qlen %d ovq "
- "%ld block %ld\n",
- asyp->rxints, asyp->rxchar, asyp->rxput, asyp->rxbuf, asyp->rxq,
- len_q(asyp->rcvq), asyp->rxovq, asyp->rxblock);
- tprintf(" TX: ints %lu gets %lu chars %lu txqueue %d qlen %d ovq %ld "
- "block %ld\n",
- asyp->txints, asyp->txget, asyp->txchar, asyp->txq,
- len_q(asyp->sndq), asyp->txovq, asyp->txblock);
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Serial transmit process, common to all protocols */
-
- /*
- * Yes, this badly needs to be rewritten.
- */
-
- static void
- asy_tx(dev, p1, p2)
- int dev;
- void *p1, *p2;
- {
- register struct mbuf *bp;
- struct asy *asyp;
- int c, l, off;
-
- asyp = &Asy[dev];
- if ((c = asyp->txq) <= 0)
- c = 1;
- for (;;)
- {
- while (asyp->sndq == NULLBUF)
- {
- if (!(c = asyp->txq))
- c = 1;
- if (pwait(&asyp->sndq) != 0)
- return;
- asyp->txints++;
- }
- bp = dequeue(&asyp->sndq);
- asyp->txget++;
- off = 0;
- while (bp != NULLBUF)
- {
- l = write(asyp->fd, bp->data + off, (size_t)bp->cnt - off);
- if (l == -1 && errno != EWOULDBLOCK)
- {
- tprintf("asy_tx(%d): write error %d, shutting down\n", dev,
- errno);
- return;
- }
- if (l == -1)
- l = 0;
- asyp->txchar += l;
- if (l == bp->cnt - off)
- {
- bp = free_mbuf(bp);
- off = 0;
- }
- else
- {
- asyp->txblock++;
- pwait(NULL);
- off += l;
- }
- }
- if (--c < 1 && asyp->txq > 1)
- {
- asyp->txovq++;
- pwait(NULL);
- }
- }
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Send a message on the specified serial line */
- int
- asy_send(dev,bp)
- int dev;
- struct mbuf *bp;
- {
- struct asy *asyp;
-
- if(dev < 0 || dev >= ASY_MAX){
- free_p(bp);
- return -1;
- }
- asyp = &Asy[dev];
-
- if(asyp->iface == NULLIF)
- free_p(bp);
- else
- enqueue(&asyp->sndq, bp);
- return 0;
- }
-
- /* stub, CD not enabled at present */
-
- int
- carrier_detect(dev)
- int dev;
- {
- return 1; /* assume always on, with CLOCAL it is! */
- }
-
- /*---------------------------------------------------------------------------*/
-
- int
- doasyconfig(ac, av, p)
- int ac;
- char **av;
- void *p;
- {
- struct iface *ip;
- struct asy *ap;
-
- if (ac < 3)
- return 1;
- if (!(ip = if_lookup(av[1])))
- {
- tprintf("Interface %s unknown\n", av[1]);
- return 1;
- }
- for (ap = Asy; ap < &Asy[ASY_MAX]; ap++)
- {
- if (ap->iface == ip)
- break;
- }
- if (!ap)
- {
- tprintf("Interface %s not asy\n", av[1]);
- return 1;
- }
- return subcmd(AsyPcmds, ac - 1, av + 1, ap);
- }
-
- static int
- doasy2stat(ac, av, d)
- int ac;
- char **av;
- void *d;
- {
- pasy((struct asy *) d);
- return 0;
- }
-
- static int
- dorxqueue(ac, av, d)
- int ac;
- char **av;
- void *d;
- {
- return setint(&((struct asy *) d)->rxq, "Receive queue size", ac, av);
- }
-
- static int
- dotxqueue(ac, av, d)
- int ac;
- char **av;
- void *d;
- {
- return setint(&((struct asy *) d)->txq, "Transmit queue size", ac, av);
- }
-
- static int
- dobufsize(ac, av, d)
- int ac;
- char **av;
- void *d;
- {
- return setuns(&((struct asy *) d)->rxbuf, "Receive buffer size", ac, av);
- }
-